use autometrics::{autometrics, prometheus_exporter};
#[cfg(feature = "prometheus-client")]
use prometheus_client::metrics::{counter::Counter, family::Family};

/// Example HTTP handler function
#[autometrics]
pub fn get_index_handler() -> Result<String, ()> {
    Ok("Hello world!".to_string())
}

// Run the example with `--features=metrics` to use the `metrics` crate to define additional metrics.
#[cfg(feature = "metrics")]
pub fn function_with_custom_metrics_metric() {
    use metrics::counter;

    counter!("custom_metrics_counter", 1, "foo" => "bar");
}

// Run the example with `--features=opentelemetry` to use the `opentelemetry` crate to define additional metrics.
#[cfg(feature = "opentelemetry")]
pub fn function_with_custom_opentelemetry_metric() {
    use once_cell::sync::Lazy;
    use opentelemetry::{global, metrics::Counter, KeyValue};

    static COUNTER: Lazy<Counter<u64>> = Lazy::new(|| {
        global::meter("")
            .u64_counter("custom_opentelemetry_counter")
            .init()
    });
    COUNTER.add(1, &[KeyValue::new("foo", "bar")]);
}

// Run the example with `--features=prometheus` to use the `prometheus` crate to define additional metrics.
#[cfg(feature = "prometheus")]
pub fn function_with_custom_prometheus_metric() {
    use once_cell::sync::Lazy;
    use prometheus::{register_int_counter_vec, IntCounterVec};

    static COUNTER: Lazy<IntCounterVec> = Lazy::new(|| {
        register_int_counter_vec!(
            "custom_prometheus_counter",
            "Custom counter",
            &["foo", "library"]
        )
        .unwrap()
    });

    COUNTER.with_label_values(&["bar", "prometheus"]).inc();
}

#[cfg(feature = "prometheus-client")]
static CUSTOM_COUNTER: OnceCell<Family<Vec<(&str, &str)>, Counter>> = OnceCell::new();

#[cfg(feature = "prometheus-client")]
pub fn function_with_custom_prometheus_client_metric() {
    CUSTOM_COUNTER
        .get()
        .unwrap()
        .get_or_create(&vec![("foo", "bar")])
        .inc();
}

pub fn main() {
    // The global metrics exporter will collect the metrics generated by
    // autometrics as well as any custom metrics you add
    #[cfg(not(feature = "prometheus-client"))]
    prometheus_exporter::init();

    #[cfg(feature = "prometheus-client")]
    {
        use autometrics::settings::AutometricsSettingsBuilder;
        use prometheus_client::registry::Registry;

        let mut registry = <Registry>::default();
        let custom_counter = Family::<Vec<(&str, &str)>, Counter>::default();
        registry.register("custom_counter", "Custom counter", custom_counter.clone());
        CUSTOM_COUNTER.set(custom_counter).unwrap();

        AutometricsSettings::builder()
            .prometheus_client_registry(registry)
            .init();
    }

    for _i in 0..5 {
        get_index_handler().unwrap();

        #[cfg(feature = "metrics")]
        function_with_custom_metrics_metric();
        #[cfg(feature = "opentelemetry")]
        function_with_custom_opentelemetry_metric();
        #[cfg(feature = "prometheus")]
        function_with_custom_prometheus_metric();
        #[cfg(feature = "prometheus-client")]
        function_with_custom_prometheus_client_metric();
    }

    // Normally, you would expose a /metrics endpoint that Prometheus would scrape
    // but in this example, we're just printing out the metrics in the Prometheus text format
    println!("{}", prometheus_exporter::encode_to_string().unwrap());
}
